/**
 * @file SerialPort.h
 * @brief AT89串口头文件
 * @details AT89C52
 * 摘自STC-ISP
 * @version ver1.0
 * @date 2022年4月28日
 * @author cmm
 * @note
 */

#include "SerialPort.h"
#include "fifo.h"

static uint8_t txBuff[__TX_BUFF__];
static uint8_t rxBuff[__RX_BUFF__];
typedef struct SerialPort
{
    tFifo txBuffer;
    tFifo rxBuffer;
} SerialPortData_t;
static SerialPortData_t m_SerialData;
bit busy;
void SerialPortInit()
{
#if (PARITYBIT == NONE_PARITY)
    PCON &= 0x7F;  // 波特率不倍速
    SCON = 0x50;   // 8位数据,可变波特率
    SCON &= ~0xF0; // 8-bit variable UART
    SCON |= 0x50;  // 8-bit variable UART
#elif (PARITYBIT == ODD_PARITY) || (PARITYBIT == EVEN_PARITY) || (PARITYBIT == MARK_PARITY)
    SCON = 0xda; // 9-bit variable UART, parity bit initial to 1
#elif (PARITYBIT == SPACE_PARITY)
    SCON = 0xd2; // 9-bit variable UART, parity bit initial to 0
#endif

#if SERIAL_MODE == SERIAL_MODE_1T
    AUXR |= 0x40;                                // 定时器时钟1T模式
    AUXR &= 0xFE;                                // 串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;                                // 设置定时器模式
#else
#error "Invalid serial mode"
#endif
    TL1 = (65536 - (FOSC / SERIAL_MODE / BAUD)); // 设置定时初始值
    TH1 = (65536 - (FOSC / SERIAL_MODE / BAUD)) >> 8;
    FifoInit(&m_SerialData.txBuffer, txBuff, sizeof(txBuff));
    FifoInit(&m_SerialData.rxBuffer, rxBuff, sizeof(rxBuff));
    ET1 = 0; // 禁止定时器%d中断
    TR1 = 1; // 定时器1开始计时
    ES = 1;  // Enable UART interrupt
    EA = 1;  // Open master interrupt switch
}

void fifoRx(uint8_t buff)
{
    FifoPush(&m_SerialData.rxBuffer, buff);
}
/*----------------------------
UART interrupt service routine
----------------------------*/
void Uart_Isr() interrupt 4
{
    if (RI)
    {
        RI = 0; // Clear receive interrupt flag
        FifoPush_IT(&m_SerialData.rxBuffer, SBUF);
    }
    if (TI)
    {
        TI = 0; // Clear transmit interrupt flag
        if (!IsFifoEmpty(&m_SerialData.txBuffer))
        {
            SBUF = FifoPop_IT(&m_SerialData.txBuffer);
        }
        else
        {
            busy = 0; // Clear transmit busy flag
        }
    }
}

/*----------------------------
Send a byte data to UART
Input: dat (data to be sent)
Output:None
----------------------------*/
void SendData(uint8_t dat)
{
    while (IsFifoFull(&m_SerialData.txBuffer))
        ; // Wait for the completion of the previous data is sent
    FifoPush(&m_SerialData.txBuffer, dat);
    ACC = dat; // Calculate the even parity bit P (PSW.0)
    if (P)     // Set the parity bit according to P
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 0; // Set parity bit to 0
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 1; // Set parity bit to 1
#endif
    }
    else
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 1; // Set parity bit to 1
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 0; // Set parity bit to 0
#endif
    }
    if (busy == 0)
    {
        busy = 1;
        TI = 1; // 启动发送
    }
}

/*----------------------------
Send a string to UART
Input: s (address of string)
Output:None
----------------------------*/
void SendString(char *s)
{
    while (*s) // Check the end of the string
    {
        SendData(*s++); // Send current char and increment string ptr
    }
}
#ifdef __RX_BUFF__
uint8_t GetRxCount()
{
    return FifoUsedSpace(&m_SerialData.rxBuffer);
}
bool Getchar(uint8_t *byte)
{
    if (GetRxCount())
    {
        *byte = FifoPop(&m_SerialData.rxBuffer);
        return true;
    }
    return false;
}

#endif
